
#include <BGridLayout>
#include <BVBoxLayout>
#include <BHBoxLayout>
#include <BLabel>
#include <BShape>
#include <BNode>
#include <BStyle>
#include <BGeometry>
#include <BMesh>

#include "TransformNote.h"

TransformNote::TransformNote(BWidget* parent) : Note(parent)
{
	this->setTitle("Transform");

	BLabel* positionLabel = new BLabel("Position");
	positionLabel->setAlign(Align_LeftCenter);
	BGridLayout* positionLayout = new BGridLayout();
	{
		_positionXSpinBox = new BRealSpinBox();
		_positionYSpinBox = new BRealSpinBox();
		_positionZSpinBox = new BRealSpinBox();
		positionLayout->addWidget(0, 0, new BLabel("X"));
		positionLayout->addWidget(0, 1, _positionXSpinBox);
		positionLayout->addWidget(1, 0, new BLabel("Y"));
		positionLayout->addWidget(1, 1, _positionYSpinBox);
		positionLayout->addWidget(2, 0, new BLabel("Z"));
		positionLayout->addWidget(2, 1, _positionZSpinBox);
		//positionLayout->setColumnPolicy(0, Policy_Preferred);
	}

	BLabel* rotationLabel = new BLabel("Rotation");
	rotationLabel->setAlign(Align_LeftCenter);
	BGridLayout* rotationLayout = new BGridLayout();
	{
		_rotationXSpinBox = new BRealSpinBox();
		_rotationYSpinBox = new BRealSpinBox();
		_rotationZSpinBox = new BRealSpinBox();
		rotationLayout->addWidget(0, 0, new BLabel("X"));
		rotationLayout->addWidget(0, 1, _rotationXSpinBox);
		rotationLayout->addWidget(1, 0, new BLabel("Y"));
		rotationLayout->addWidget(1, 1, _rotationYSpinBox);
		rotationLayout->addWidget(2, 0, new BLabel("Z"));
		rotationLayout->addWidget(2, 1, _rotationZSpinBox);
	}

	BLabel* scalingLabel = new BLabel("Scaling");
	scalingLabel->setAlign(Align_LeftCenter);
	{
		_collapseScaleButton = new BButton("collapse");
		_collapseScaleButton->setForm(Form_IconAlone);
		BHBoxLayout* titleLayout = new BHBoxLayout(scalingLabel);
		titleLayout->addSpring();
		titleLayout->addWidget(_collapseScaleButton);
	}
	BGridLayout* scalingLayout = new BGridLayout();
	{
		_scalingXSpinBox = new BRealSpinBox();
		_scalingYSpinBox = new BRealSpinBox();
		_scalingZSpinBox = new BRealSpinBox();
		scalingLayout->addWidget(0, 0, new BLabel("X"));
		scalingLayout->addWidget(0, 1, _scalingXSpinBox);
		scalingLayout->addWidget(1, 0, new BLabel("Y"));
		scalingLayout->addWidget(1, 1, _scalingYSpinBox);
		scalingLayout->addWidget(2, 0, new BLabel("Z"));
		scalingLayout->addWidget(2, 1, _scalingZSpinBox);
	}

	BVBoxLayout* vlayout = new BVBoxLayout(this);
	vlayout->addWidget(positionLabel);
	vlayout->addLayout(positionLayout);
	vlayout->addWidget(rotationLabel);
	vlayout->addLayout(rotationLayout);
	vlayout->addWidget(scalingLabel);
	vlayout->addLayout(scalingLayout);

	connect(this, Signal_AssetChanged, &TransformNote::slotAssetChanged);

	connect(_positionXSpinBox, Signal_EditFinished, &TransformNote::slotPositionEditFinished);
	connect(_positionYSpinBox, Signal_EditFinished, &TransformNote::slotPositionEditFinished);
	connect(_positionZSpinBox, Signal_EditFinished, &TransformNote::slotPositionEditFinished);

	connect(_rotationXSpinBox, Signal_EditFinished, &TransformNote::slotRotationEditFinished);
	connect(_rotationYSpinBox, Signal_EditFinished, &TransformNote::slotRotationEditFinished);
	connect(_rotationZSpinBox, Signal_EditFinished, &TransformNote::slotRotationEditFinished);

	connect(_collapseScaleButton, Signal_Clicked, &TransformNote::slotCollapseScaleButtonClicked);
	connect(_scalingXSpinBox, Signal_EditFinished, &TransformNote::slotScalingEditFinished);
	connect(_scalingYSpinBox, Signal_EditFinished, &TransformNote::slotScalingEditFinished);
	connect(_scalingZSpinBox, Signal_EditFinished, &TransformNote::slotScalingEditFinished);

	connect("target-changed", &TransformNote::slotTargetChanged);

}
TransformNote::~TransformNote()
{

}

BSize TransformNote::sizeHint() const
{
	BSize hsize = Note::sizeHint();
	return hsize;
}

void TransformNote::scaleShape(BShape* shape)
{
	BReal sx = _scalingXSpinBox->value();
	BReal sy = _scalingYSpinBox->value();
	BReal sz = _scalingZSpinBox->value();
	if (BGeometry* geometry = dynamic_cast<BGeometry*>(shape))
	{
		BVectorArray* vertices = geometry->vertices();
		for (int i = 0; i < vertices->size(); i++)
		{
			BVector& v = vertices->at(i);
			v.x() *= sx;
			v.y() *= sy;
			v.z() *= sz;
		}
		geometry->setVertices(vertices);
		return;
	}
	if (BMesh* mesh = dynamic_cast<BMesh*>(shape))
	{
		BVectorArray* vertices = mesh->vertices();
		for (int i = 0; i < vertices->size(); i++)
		{
			BVector& v = vertices->at(i);
			v.x() *= sx;
			v.y() *= sy;
			v.z() *= sz;
		}
		mesh->setVertices(vertices);
		return;
	}
}
void TransformNote::scaleNode(BNode* node)
{
	for (int i = 0; i < node->shapeCount(); i++)
	{
		BShape* shape = node->shape(i);
		scaleShape(shape);
	}
}
void TransformNote::scaleGroup(BGroup* group)
{
	for (int i = 0; i < group->shapeCount(); i++)
	{
		BShape* shape = group->shape(i);
		scaleShape(shape);
	}
	for (int i = 0; i < group->nodeCount(); i++)
	{
		BNode* node = group->node(i);
		scaleNode(node);
	}
	for (int i = 0; i < group->childCount(); i++)
	{
		BGroup* child = group->child(i);
		scaleGroup(child);
	}
}

void TransformNote::slotAssetChanged(BObject* object, const BValue& value)
{
	_matrix = (const BMatrix&)value;

	BVector position = _matrix.position();
	_positionXSpinBox->setValue(position.x());
	_positionYSpinBox->setValue(position.y());
	_positionZSpinBox->setValue(position.z());

	BVector rotation = _matrix.euler();
	_rotationXSpinBox->setValue(bRTD(rotation.x()));
	_rotationYSpinBox->setValue(bRTD(rotation.y()));
	_rotationZSpinBox->setValue(bRTD(rotation.z()));

	BVector scaling = _matrix.scale();
	_scalingXSpinBox->setValue(scaling.x());
	_scalingYSpinBox->setValue(scaling.y());
	_scalingZSpinBox->setValue(scaling.z());
}
void TransformNote::slotPositionEditFinished(BObject* object, const BValue& value)
{
	BReal x = _positionXSpinBox->value();
	BReal y = _positionYSpinBox->value();
	BReal z = _positionZSpinBox->value();
	_matrix.setPosition(x, y, z);
	emit("matrix-changed", _matrix);
}
void TransformNote::slotRotationEditFinished(BObject* object, const BValue& value)
{
	BReal x = _rotationXSpinBox->value();
	BReal y = _rotationYSpinBox->value();
	BReal z = _rotationZSpinBox->value();
	x = bDTR(x);
	y = bDTR(y);
	z = bDTR(z);
	_matrix.setEuler(x, y, z);
	emit("matrix-changed", _matrix);
}
void TransformNote::slotCollapseScaleButtonClicked(BObject* object, const BValue& value)
{
	if (BShape* shape = _target->shape())
	{
		scaleShape(shape);
		shape->setScale(1, 1, 1);
	}
	else if (BNode* node = _target->node())
	{
		scaleNode(node);
		node->setScale(1, 1, 1);
	}
	else if (BGroup* group = _target->group())
	{
		scaleGroup(group);
	}
	_scalingXSpinBox->setValue(1);
	_scalingYSpinBox->setValue(1);
	_scalingZSpinBox->setValue(1);
}
void TransformNote::slotScalingEditFinished(BObject* object, const BValue& value)
{
	BReal x = _scalingXSpinBox->value();
	BReal y = _scalingYSpinBox->value();
	BReal z = _scalingZSpinBox->value();
	_matrix.setScale(x, y, z);
	emit("matrix-changed", _matrix);
}
void TransformNote::slotTargetChanged(BObject* object, const BValue& value)
{
	_target = (Target*)value;
}

void TransformNote::styleEvent(const BEvent& event)
{
	Note::styleEvent(event);
	const BStyle* style = event.value();
	_collapseScaleButton->setIcon(style->icon("collapse"));
}
